# 作者： 李泉志
# 2025年01月09日16时06分秒
# 2947029073@qq.com

"""
11 异常
目标
• 异常的概念
• 捕获异常
• 异常的传递（函数，方法）
• 抛出异常

01. 异常的概念
• 程序在运行时，如果Python解释器遇到到一个错误，会停止进程的执行，并且提示一些错误信息，这就是异常
• 程序停止执行并且提示错误信息这个动作，我们通常称之为：抛出(raise)异常
• 程序开发时，很难将所有的特殊情况都处理的面面俱到，通过异常捕获可以针对突发事件做集中的处理，从而保证程序的稳定性和健壮性

02. 捕获异常
2.1 简单的捕获异常语法
• 在程序开发中，如果对某些代码的执行不能确定是否正确可以增加try(尝试)来捕获异常
• 捕获异常最简单的语法格式：
try:
    尝试执行的代码
except:
    出现错误的处理
• try尝试，下方编写要尝试代码，不确定是否能够正常执行的代码
• except如果不是，下方编写尝试失败的代码
"""


def use_exception1():
    while True:
        try:
            # 提示用户输入一个数字
            num = int(input("请输入数字："))
            break
        except:
            print("请输入正确的数字")


"""
2.2 错误类型捕获
• 在程序执行时，可能会遇到不同类型的异常，并且需要针对不同类型的异常，做出不同的响应，这个时候，就需要捕获错误类型了
• 语法如下：
try:
    # 尝试执行的代码
    pass
except 错误类型 1:
    # 针对错误类型 1，对应的代码处理
    pass
except (错误类型 2, 错误类型 3):
    # 针对错误类型 2 和 3，对应的代码处理
    pass
except Exception as result:
    print("未知错误 %s" % result)
• 当 Python 解释器抛出异常时，最后一行错误信息的第一个单词，就是错误类
型

捕获未知错误
• 在开发时，要预判到所有可能出现的错误，还是有一定难度的
• 如果希望程序无论出现任何错误，都不会因为Python解释器抛出异常而被终止，
    可以再增加一个except(记日志)
语法如下：
except Exception as result:
    print("未知错误 %s" % result)

2.3 异常捕获完整语法
• 在实际开发中，为了能够处理复杂的异常情况，完整的异常语法如下：
提示：
• 有关完整语法的应用场景，在后续学习中，结合实际的案例会更好理解
• 现在先对这个语法结构有个印象即可
try:
    # 尝试执行的代码
    pass
except 错误类型 1:
    # 针对错误类型 1，对应的代码处理
    pass
except 错误类型 2:
    # 针对错误类型 2，对应的代码处理
    pass
except (错误类型 3, 错误类型 4):
    # 针对错误类型 3 和 4，对应的代码处理
    pass
except Exception as result:
    # 打印错误信息
    print(result)
else:
    # 没有异常才会执行的代码
    pass
finally:
    # 无论是否有异常，都会执行的代码
    print("无论是否有异常，都会执行的代码")

• else只有在没有异常时才会执行的代码
• finally无论是否有异常，都会执行的代码（不受 return 影响）
"""
import test_exception_module


def use_exception2():
    """
    1. 提示用户输入一个整数
    2.使用8除以用户输入的整数并且输出
    :return: 
    """
    try:
        num = int(input("请输入整数："))
        result = 8 / num  # /是float除法，//s是整数除法(向下取整)
        print(result)
    except ValueError:
        print("请输入正确的整数")
        return
    # except ZeroDivisionError:
    #     print("除 0 错误")
    except Exception as e:
        print("未知错误 %s" % e)
    else:
        print("正常执行")
    finally:  # 若无finally直接print,若前面return,则不执行；但有finally，都会执行
        print("程序结束，但不保证正确")


def use_exception3():
    """
    定位异常发生的文件(模块)和具体行数
    :return:
    """
    try:
        test_exception_module.test()
    except Exception as e:
        print(e)
        print(e.__traceback__.tb_frame.f_globals["__file__"])  # 发生异常的当前文件
        tb = e.__traceback__
        while tb.tb_next:
            tb = tb.tb_next
        print(tb.tb_frame.f_globals["__file__"])  # 发生异常的代码所在的源文件
        print(e.__traceback__.tb_lineno)  # 发生异常所在的行数


"""
03. 异常的传递
• 异常的传递 —— 当函数/方法执行出现异常，会将异常传递给函数/方法的调用一方
• 如果传递到主程序，仍然没有异常处理，程序才会被终止
提示
• 在开发中，可以在主函数中增加异常捕获
• 而在主函数中调用的其他函数，只要出现异常，都会传递到主函数的异常捕获中
• 这样就不需要在代码中，增加大量的异常捕获，能够保证代码的整洁
"""


def demo1():
    num1 = int(input("请输入一个数字："))
    print('num1')
    return num1


def demo2():
    num2 = demo1()
    print('num2')
    return num2


def use_exception4():
    try:
        print(demo2())
    except Exception as e:
        print('发生异常 %s' % e)


if __name__ == '__main__':
    # use_exception1()
    # use_exception2()
    use_exception3()
    # use_exception4()  # 发生异常后直接向上层抛出异常，不执行后续代码
